﻿using System;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
using ActivateYourGlutes.Model.Internal;
using AutoMapper;

namespace ActivateYourGlutes.Model.Providers
{
    public class ProviderBase : IProviderBase
    {
        private readonly ActivateYourGlutesEntities _db;

        protected ProviderBase(IEntityModelFactory factory)
        {
            _db = factory.Model;
        }

        protected ActivateYourGlutesEntities Db
        {
            get { return _db; }
        }

        #region IProviderBase Members

        /// <summary>
        /// Retrieves the current account based on a security principal object 
        /// </summary>
        public Contracts.Account CurrentAccount(IPrincipal user)
        {
            string username = user.Identity.Name;
            var account = _db.Accounts.Include("UnitOfLength").
                Include("UnitOfWeight").
                Include("PrimaryMeasurementType").
                Include("SecondaryMeasurementType").
                Where(ac => ac.Username == username).FirstOrDefault();

            return Mapper.Map<Account, Contracts.Account>(account);
        }

        #endregion

        protected void TryUpdateModel(object destination, object source, string[] properties)
        {
            if (destination == null)
                throw new ArgumentNullException("destination");
            if (source == null)
                throw new ArgumentNullException("source");
            if (properties == null || properties.Length == 0)
                throw new ArgumentNullException("properties");
            Type destinationType = destination.GetType();
            Type sourceType = source.GetType();

            foreach (string propertyName in properties)
            {
                PropertyInfo destinationProperty = destinationType.GetProperty(propertyName);
                PropertyInfo sourceProperty = sourceType.GetProperty(propertyName);

                if (destinationProperty == null || sourceProperty == null)
                    throw new ModelException("Source and/or destination properties do not exist");

                if (destinationProperty.PropertyType != sourceProperty.PropertyType)
                    throw new ModelException(
                        "Properties exist on both source and destination but are of differing types");

                destinationProperty.SetValue(destination, sourceProperty.GetValue(source, null), null);
            }
        }
    }
}